package org.foreningsgatan.genetics.racers;

import static org.foreningsgatan.genetics.racers.CommonMath.within;
import static org.foreningsgatan.genetics.racers.Configuration.sHeight;
import static org.foreningsgatan.genetics.racers.Configuration.sWidth;

import org.foreningsgatan.genetics.ResultSet;
import org.foreningsgatan.genetics.SimulationEnvironment;

public class RacingSimulation implements
		SimulationEnvironment<Sources, Actions> {
	private Car car;
	private CheckPoints checkpoints;
	private int actionsPerformed;

	public RacingSimulation() {
		this.checkpoints = new CheckPoints();
		this.car = null;
	}
	
	public Car getCar() {
		return car;
	}
	
	public CheckPoints getCheckpoints() {
		return checkpoints;
	}

	@Override
	public boolean simulationActive() {
		if (car.targetCheckpointIndex == Configuration.sCheckpoints) {
			return false;
		}
		
		return 
			within(car.position.getX(), (double) -sWidth / 2, (double) sWidth / 2) && 
			within(car.position.getY(), (double) -sHeight / 2, (double) sHeight / 2) &&
			(car.fuel > 0) && (car.tick < Configuration.sTickLimit);
	}

	@Override
	public void resetAll() {
		car = new Car(this);
	}

	@Override
	public float read(Sources dataSource) {
		return car.read(dataSource);
	}

	@Override
	public void perform(Actions action) {
		if (action != Actions.Idle) {
			actionsPerformed++;
		}
		
		car.perform(action);
	}

	@Override
	public void act() {
		car.act();
	}

	@Override
	public void applyResult(ResultSet resultSet) {
		resultSet.put(ResultType.Points, car.targetCheckpointIndex);
		resultSet.put(ResultType.FuelLeft, car.fuel);
		resultSet.put(ResultType.TickPassed,  car.tick);
		resultSet.put(ResultType.ActionsPerformed, actionsPerformed);
	}

	@Override
	public SimulationEnvironment<Sources, Actions> cloneAndReset() {
		RacingSimulation clone = new RacingSimulation();
		clone.resetAll();
		
		return clone;
	}

	@Override
	public int compare(ResultSet o1, ResultSet o2) {
		int points1 = o1.get(ResultType.Points).intValue();
		int points2 = o2.get(ResultType.Points).intValue();
		
		// int fuelLeft1 = o1.get(ResultType.FuelLeft).intValue();
		// int fuelLeft2 = o2.get(ResultType.FuelLeft).intValue();
		
		int tickPassed1 = o1.get(ResultType.TickPassed).intValue();
		int tickPassed2 = o2.get(ResultType.TickPassed).intValue();
		
		// int nodeLength1 = o1.get(DefaultResultType.NodeLength).intValue();
		// int nodeLength2 = o2.get(DefaultResultType.NodeLength).intValue();
		
		// int actionsPerformed1 = o1.get(ResultType.ActionsPerformed).intValue();
		// int actionsPerformed2 = o2.get(ResultType.ActionsPerformed).intValue();
		
		if (points1 != points2) {
			return Double.compare(points2, points1);
		} else {
			return Double.compare(tickPassed1, tickPassed2);
		}
	}
	
	enum ResultType {
		Points, FuelLeft, TickPassed, ActionsPerformed
	}
}
